package com.dc.dbus.transport.netty.server;

import java.io.IOException;

import com.dc.dbus.transport.commons.ServerAddress;
import com.dc.dbus.transport.commons.ServerSideReceiver;
import com.dc.dbus.transport.commons.ServerSideTransport;
import com.dc.dbus.transport.netty.MsgBack;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

public class NettyServerSideTransport implements ServerSideTransport {

	protected final ServerAddress address;
	
	protected final ClientChannelCenter clientChannelCenter;
	
	protected volatile EventLoopGroup bossGroup;
	protected volatile EventLoopGroup workerGroup;
	
	public NettyServerSideTransport(ServerAddress address) throws IOException {
		
		this.address = address;
		
		this.clientChannelCenter = new ClientChannelCenter();
	}
	
	@Override
	public void startServerSideReceiver(ServerSideReceiver serverSideReceiver) {
		
		bossGroup = new NioEventLoopGroup();
		workerGroup = new NioEventLoopGroup();
		
		try {
			
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup);
			b.childOption(ChannelOption.TCP_NODELAY, true);
			b.channel(NioServerSocketChannel.class);
			b.childHandler(new MainHandlerInitializer(serverSideReceiver, clientChannelCenter));

			// 服务器绑定端口监听
			ChannelFuture f = b.bind(address.getPorts()[0]).sync();
			// 监听服务器关闭监听
			f.channel().closeFuture().addListener(new GenericFutureListener<Future<Void>>() {
				@Override
				public void operationComplete(Future<Void> future) throws Exception {
					bossGroup.shutdownGracefully();
					workerGroup.shutdownGracefully();
				}
			});

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	@Override
	public void sendBack(String source, long replyForMsgId, int replyForCmd, int resultCode, Object returnObj) {
		
		clientChannelCenter.sendToClient(source, new MsgBack(replyForMsgId, replyForCmd, resultCode, returnObj));
	}

	@Override
	public void close() {
		
		if (bossGroup != null) {
			bossGroup.shutdownGracefully();
		}
		
		if (workerGroup != null) {
			workerGroup.shutdownGracefully();
		}
	}

}
